<?php
namespace Game\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Game\Action\AbstractAction;
use Game\Exception\IsDeadException;

/**
 * @Entity
 * @Table(name="game_character", indexes={@index(name="char_type_idx", columns={"char_type"})})
 * @InheritanceType("SINGLE_TABLE")
 * @DiscriminatorColumn(name="char_type", type="string")
 * @DiscriminatorMap({ "pers" = "Person", "bot"="Bot" })
 */
abstract class Character
{
    /**
     * @Id
     * @Column(type="integer")
     * @GeneratedValue(strategy="AUTO")
     * @var integer
     **/
    protected $id;

    /**
     * @Column(type="string", length=255)
     * @var string
     */
    protected $name;

    /**
     * @Column(type="integer")
     * @var integer
     */
    protected $max_hp;

    /**
     * @Column(type="integer")
     * @var integer
     */
    protected $hp;

    /**
     * @Column(type="integer")
     * @var integer
     */
    protected $level;

    /**
     * @Column(type="integer")
     * @var integer
     */
    protected $exp;

    /**
     * @Column(type="integer")
     * @var integer
     */
    protected $power;

    /**
     * @Column(type="integer")
     * @var integer
     */
    protected $agility;

    /**
     * @Column(type="integer")
     * @var integer
     */
    protected $accuracy;

    /**
     * @Column(type="integer")
     * @var integer
     */
    protected $luck;

    /**
     * @Column(type="integer")
     * @var integer
     */
    protected $base_damage;

    /**
     * @Column(type="integer")
     * @var integer
     */
    protected $base_armor;

    /**
     * @Column(type="integer")
     * @var integer
     */
    protected $money;

    /**
     * @OneToMany(targetEntity="Item", mappedBy="character")
     */
    protected $items;

    /**
     * @ManyToOne(targetEntity="Environment", inversedBy="characters")
     * @JoinColumn(name="environment_id", referencedColumnName="id", nullable=true)
     */
    protected $environment;

    /**
     * Character actions collection
     * @var ArrayCollection
     */
    protected $actions;

    public function __construct()
    {
        $this->actions = new ArrayCollection();
        $this->items = new ArrayCollection();
    }

    public function __toString()
    {
        return $this->getName();
    }

    public function addAction(AbstractAction $action)
    {
        if( is_null($this->actions) ) $this->actions = new ArrayCollection();
        $code = $action->getCode();
        $action->setOwner($this);
        $this->actions->set($code, $action);
    }

    /**
     * Get action by code
     * @param string $code
     * @return \Game\Action\AbstractAction
     */
    public function getAction($code)
    {
        return $this->actions->get($code);
    }

    /**
     * Get actions collection
     * @return ArrayCollection
     */
    public function getActions()
    {
        return $this->actions;
    }

    public function validateCommand($command)
    {
        return $this->getActions()->containsKey($command);
    }

    /**
     * Causes damage to character
     * @param type $damage
     */
    public function makeDamage($damage)
    {
        $new_hp = $this->getHp() - $damage;
        if( $new_hp < 0 ) $new_hp = 0;
        $this->setHp($new_hp);
    }

    public function checkForDeath()
    {
        if( $this->isDead() )
            throw new IsDeadException($this.' is dead man');
    }

    /**
     *
     */
    public function makeDeathByHp()
    {
        throw new IsDeadException($this.' is dead man');
    }

    /**
     *
     * @return boolean
     */
    public function isDead()
    {
        return ($this->getHp() <= 0);
    }

    /**
     *
     * @return boolean
     */
    public function isAlive()
    {
        return !$this->isDead();
    }

    public function fromArray(array $array)
    {
        foreach( $array as $key => $value )
        {
            if( property_exists($this, $key) )
                $this->$key = $value;
        }
    }

    public function getGeneralProperties()
    {
        return array(
            'accuracy' => $this->accuracy,
            'agility' => $this->agility,
            'base_armor' => $this->base_armor,
            'base_damage' => $this->base_damage,
            'luck' => $this->luck,
            'power' => $this->power,
        );
    }

    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     * @return Character
     */
    public function setName($name)
    {
        $this->name = $name;
        return $this;
    }

    /**
     * Get name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set max hp
     *
     * @param integer $hp
     * @return Character
     */
    public function setMaxHp($hp)
    {
        $this->max_hp = $hp;
        return $this;
    }

    /**
     * Get max hp
     *
     * @return integer
     */
    public function getMaxHp()
    {
        return $this->max_hp;
    }

    /**
     * Set hp
     *
     * @param integer $hp
     * @return Character
     */
    public function setHp($hp)
    {
        $this->hp = $hp;
        return $this;
    }

    /**
     * Get hp
     *
     * @return integer
     */
    public function getHp()
    {
        return $this->hp;
    }

    /**
     * Set level
     *
     * @param integer $level
     * @return Character
     */
    public function setLevel($level)
    {
        $this->level = $level;
        return $this;
    }

    /**
     * Get level
     *
     * @return integer
     */
    public function getLevel()
    {
        return $this->level;
    }

    /**
     * Set exp
     *
     * @param integer $exp
     * @return Character
     */
    public function setExp($exp)
    {
        $this->exp = $exp;
        return $this;
    }

    /**
     * Get exp
     *
     * @return integer
     */
    public function getExp()
    {
        return $this->exp;
    }

    /**
     * Set power
     *
     * @param integer $power
     * @return Character
     */
    public function setPower($power)
    {
        $this->power = $power;
        return $this;
    }

    /**
     * Get power
     *
     * @return integer
     */
    public function getPower()
    {
        return $this->power;
    }

    /**
     * Set agility
     *
     * @param integer $agility
     * @return Character
     */
    public function setAgility($agility)
    {
        $this->agility = $agility;
        return $this;
    }

    /**
     * Get agility
     *
     * @return integer
     */
    public function getAgility()
    {
        return $this->agility;
    }

    /**
     * Set accuracy
     *
     * @param integer $accuracy
     * @return Character
     */
    public function setAccuracy($accuracy)
    {
        $this->accuracy = $accuracy;
        return $this;
    }

    /**
     * Get accuracy
     *
     * @return integer
     */
    public function getAccuracy()
    {
        return $this->accuracy;
    }

    /**
     * Set luck
     *
     * @param integer $luck
     * @return Character
     */
    public function setLuck($luck)
    {
        $this->luck = $luck;
        return $this;
    }

    /**
     * Get luck
     *
     * @return integer
     */
    public function getLuck()
    {
        return $this->luck;
    }

    /**
     * Set base_damage
     *
     * @param integer $baseDamage
     * @return Character
     */
    public function setBaseDamage($baseDamage)
    {
        $this->base_damage = $baseDamage;
        return $this;
    }

    /**
     * Get base_damage
     *
     * @return integer
     */
    public function getBaseDamage()
    {
        return $this->base_damage;
    }

    /**
     * Set base_armor
     *
     * @param integer $baseArmor
     * @return Character
     */
    public function setBaseArmor($baseArmor)
    {
        $this->base_armor = $baseArmor;
        return $this;
    }

    /**
     * Get base_armor
     *
     * @return integer
     */
    public function getBaseArmor()
    {
        return $this->base_armor;
    }

    /**
     * Set money
     *
     * @param integer $money
     * @return Character
     */
    public function setMoney($money)
    {
        $this->money = $money;
        return $this;
    }

    /**
     * Get money
     *
     * @return integer
     */
    public function getMoney()
    {
        return $this->money;
    }


    /**
     * Add items
     *
     * @param Game\Entity\Item $items
     * @return Character
     */
    public function addItem(\Game\Entity\Item $items)
    {
        $this->items[] = $items;
        return $this;
    }

    /**
     * Get items
     *
     * @return Doctrine\Common\Collections\Collection
     */
    public function getItems()
    {
        return $this->items;
    }

    /**
     * Set environment
     *
     * @param Game\Entity\Environment $environment
     * @return Character
     */
    public function setEnvironment(\Game\Entity\Environment $environment = null)
    {
        $this->environment = $environment;
        return $this;
    }

    /**
     * Get environment
     *
     * @return Game\Entity\Environment
     */
    public function getEnvironment()
    {
        return $this->environment;
    }
}